package com.pfs.internal.timestamp.reports;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.servlet.http.HttpServletRequest;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.struts2.ServletActionContext;

public abstract class FatherExcel<T> {
	private PfsExcel<FatherExcel<T>> pr;
	private Map<String, Object> search;

	private Workbook wb;
	private ArrayList<Cell> hdr;
	private int ridx;
	private int cidx;
	private int sheet_index = 0;

	private Font f_10;
	private Font f_10b;
	private Font f_10bi;
	private Font f_10i;
	public CellStyle cs_center_10b;
	public CellStyle cs_center_10;
	public CellStyle cs_number_10;
	public CellStyle cs_int_10;
	public CellStyle cs_int_10b;
	public CellStyle cs_int_10bi;
	public CellStyle cs_int_10i;
	public CellStyle cs_left_10;
	public CellStyle cs_left_10b;
	public CellStyle cs_left_10bi;
	public CellStyle cs_left_10i;
	public boolean isCustom = false;
	private String kieu_chu_bold = "B";
	private String kieu_chu_italic = "I";
	private String kieu_chu_bold_italic = "BI";
	private String truong_kieu_chu = "KIEU_CHU";
	private String report_code;
	public Map<String, RegionStyle> regionMap;

	public FatherExcel() {
	}

	public FatherExcel(PfsExcel<FatherExcel<T>> pr, Map<String, Object> search) {
		this.pr = pr;
		this.search = search;
	}

	public void layout() throws Exception {
		try {
			// init cellstyle of this report
			initCellStyles();
			// get data to layout hdr
			this.hdr = getDataHdr(search);
			// get data to layout dtl: resultset
			// manager = getDataDtls(search);
			this.generate();
		} catch (Exception e) {
			throw e;
		} finally {
		}
	}

	@SuppressWarnings("rawtypes")
	public void generate() throws Exception {
		Sheet sheet = wb.getSheetAt(sheet_index);
		HSSFRow rowData;
		if (sheet == null) {
			sheet = wb.createSheet();
		}
		createFonts();
		sheet.setHorizontallyCenter(true);
		sheet_index++;
		// Layout HDR
		Iterator iterRow = sheet.rowIterator();
		while (iterRow.hasNext()) {
			rowData = (HSSFRow) iterRow.next();
			Iterator iterCell = rowData.cellIterator();
			while (iterCell.hasNext()) {
				HSSFCell cell = (HSSFCell) iterCell.next();
				if (cell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
					HSSFRichTextString richTextString = cell.getRichStringCellValue();
					for (Cell cell2 : this.hdr) {
						String key = (String) cell2.getKey();
						String value = (String) cell2.getValue();
						if (richTextString.getString().indexOf(key) > -1) {
							cell.setCellValue(new HSSFRichTextString(value));
							// cell.setCellStyle(cell2.getCs());
						}
					}
				}
			}
		}
		// Layout DTL
		int len = 0, i = 0, r = 0, c = 0, col_type = 0, stt = 0;
		double d;
		boolean kc_flag = false;
		String kc = null;
		CellStyle cs_num = cs_int_10;
		CellStyle cs_txt = cs_left_10;
		layoutDtl(ridx, cidx, getDataDtls(), sheet);
		// custom layout
		layoutCustom(sheet, r);
		sheet.setDisplayGridlines(false);
	}

	@SuppressWarnings("rawtypes")
	public abstract int layoutDtl(int row, int col, List<T> dtls, Sheet sheet);

	public abstract List<T> getDataDtls();

	public abstract int layoutCustom(Sheet sheet, int r);

	private void createFonts() {
		// create fonts
		this.f_10 = ReportUtil.createFont(wb, Font.BOLDWEIGHT_NORMAL, (short) 10, false);
		this.f_10b = ReportUtil.createFont(wb, Font.BOLDWEIGHT_BOLD, (short) 10, false);
		this.f_10bi = ReportUtil.createFont(wb, Font.BOLDWEIGHT_BOLD, (short) 10, true);
		this.f_10i = ReportUtil.createFont(wb, Font.BOLDWEIGHT_NORMAL, (short) 10, true);
		cs_center_10b = ReportUtil.createCellStyle(wb, CellStyle.ALIGN_CENTER, f_10b, (short) 0, true, (short) 1);
		cs_center_10 = ReportUtil.createCellStyle(wb, CellStyle.ALIGN_CENTER, f_10, (short) 0, true, (short) 1);
		cs_left_10 = ReportUtil.createCellStyle(wb, CellStyle.ALIGN_LEFT, f_10, (short) 0, true, (short) 1);
		cs_left_10b = ReportUtil.createCellStyle(wb, CellStyle.ALIGN_LEFT, f_10b, (short) 0, true, (short) 1);
		cs_left_10bi = ReportUtil.createCellStyle(wb, CellStyle.ALIGN_LEFT, f_10bi, (short) 0, true, (short) 1);
		cs_left_10i = ReportUtil.createCellStyle(wb, CellStyle.ALIGN_LEFT, f_10i, (short) 0, true, (short) 1);
		DataFormat df = wb.createDataFormat();
		cs_number_10 = ReportUtil.createCellStyle(wb, CellStyle.ALIGN_RIGHT, f_10, df.getFormat("#,##0.00"), false, (short) 1);
		cs_int_10 = ReportUtil.createCellStyle(wb, CellStyle.ALIGN_RIGHT, f_10, df.getFormat("#,##0"), true, (short) 1);
		cs_int_10b = ReportUtil.createCellStyle(wb, CellStyle.ALIGN_RIGHT, f_10b, df.getFormat("#,##0"), true, (short) 1);
		cs_int_10bi = ReportUtil.createCellStyle(wb, CellStyle.ALIGN_RIGHT, f_10bi, df.getFormat("#,##0"), true, (short) 1);
		cs_int_10i = ReportUtil.createCellStyle(wb, CellStyle.ALIGN_RIGHT, f_10i, df.getFormat("#,##0"), true, (short) 1);
		// ~ create fonts
	}

	public byte[] getReport() throws Exception {
		// this.getParams();
		byte[] bytes = null;
		try {
			this.report_code = (String) search.get("report_code");
			// create a workbook
			initWorkbook();
			this.layout();
			bytes = ReportUtil.wb2zip(wb, report_code);
		} catch (Exception e) {
			e.printStackTrace();
			bytes = getReportNull();
		}
		return bytes;
	}

	public void initWorkbook() throws Exception {
		try {
			// String sRootPath = request.getRealPath("/");
			// Map<String, Object> session =
			HttpServletRequest request = ServletActionContext.getRequest();
			@SuppressWarnings("deprecation")
			String sRootPath = request.getRealPath("/");
			// String sRootPath = getClass().getResource(".").getPath();
			// String file_name = sRootPath +
			// "/com/pfs/webhd/reports/templates/" + this.report_code + ".xls";
			String file_name = sRootPath + "\\Reports\\" + this.report_code + ".xls";
			// String sCompileLocation = sRootPath +
			// "\\WEB-INF\\lib\\tools.jar";
			// String file_name = servletContext.getRealPath(Constant.report_dir
			// + report_code + ".xls");
			File file = new File(file_name);
			if (file.exists()) {
				FileInputStream fis = null;
				try {
					fis = new FileInputStream(file_name);
					wb = new HSSFWorkbook(fis);
				} catch (Exception e) {
					wb = new HSSFWorkbook();
				} finally {
					if (fis != null) {
						try {
							fis.close();
						} catch (Exception e) {
						}
					}
				}
			} else {
				wb = new HSSFWorkbook();
			}
		} catch (Exception e) {
			throw e;
		}
	}

	public byte[] getReportNull() throws Exception {
		byte[] bytes = null;
		try {
			wb = new HSSFWorkbook();
			Sheet sheet = wb.createSheet();
			HSSFRow rowData = (HSSFRow) sheet.createRow(0);
			HSSFCell cell = rowData.createCell(0);
			cell.setCellValue(new HSSFRichTextString("Xảy ra lỗi kết xuất excel"));
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			ZipOutputStream zos = new ZipOutputStream(baos);
			zos.setLevel(9);
			ZipEntry ze = new ZipEntry(report_code + ".xls");
			zos.putNextEntry(ze);
			wb.write(zos);
			zos.closeEntry();
			zos.close();
			bytes = baos.toByteArray();
			baos.close();
		} catch (Exception e) {
			throw e;
		}
		return bytes;
	}

	public abstract ArrayList<Cell> getDataHdr(Map<String, Object> search) throws Exception;

	public abstract void initCellStyles();

	public PfsExcel<FatherExcel<T>> getPr() {
		return pr;
	}

	public void setPr(PfsExcel<FatherExcel<T>> pr) {
		this.pr = pr;
	}

	public Map<String, Object> getSearch() {
		return search;
	}

	public void setSearch(Map<String, Object> search) {
		this.search = search;
	}

	public Workbook getWb() {
		return wb;
	}

	public void setWb(Workbook wb) {
		this.wb = wb;
	}

	public ArrayList<Cell> getHdr() {
		return hdr;
	}

	public void setHdr(ArrayList<Cell> hdr) {
		this.hdr = hdr;
	}

	public int getSheet_index() {
		return sheet_index;
	}

	public void setSheet_index(int sheet_index) {
		this.sheet_index = sheet_index;
	}

	public int getRidx() {
		return ridx;
	}

	public void setRidx(int ridx) {
		this.ridx = ridx;
	}

	public int getCidx() {
		return cidx;
	}

	public void setCidx(int cidx) {
		this.cidx = cidx;
	}

	public Font getF_10() {
		return f_10;
	}

	public void setF_10(Font f_10) {
		this.f_10 = f_10;
	}

	public Font getF_10b() {
		return f_10b;
	}

	public void setF_10b(Font f_10b) {
		this.f_10b = f_10b;
	}

	public Font getF_10bi() {
		return f_10bi;
	}

	public void setF_10bi(Font f_10bi) {
		this.f_10bi = f_10bi;
	}

	public Font getF_10i() {
		return f_10i;
	}

	public void setF_10i(Font f_10i) {
		this.f_10i = f_10i;
	}

	public CellStyle getCs_center_10b() {
		return cs_center_10b;
	}

	public void setCs_center_10b(CellStyle cs_center_10b) {
		this.cs_center_10b = cs_center_10b;
	}

	public CellStyle getCs_center_10() {
		return cs_center_10;
	}

	public void setCs_center_10(CellStyle cs_center_10) {
		this.cs_center_10 = cs_center_10;
	}

	public CellStyle getCs_number_10() {
		return cs_number_10;
	}

	public void setCs_number_10(CellStyle cs_number_10) {
		this.cs_number_10 = cs_number_10;
	}

	public CellStyle getCs_int_10() {
		return cs_int_10;
	}

	public void setCs_int_10(CellStyle cs_int_10) {
		this.cs_int_10 = cs_int_10;
	}

	public CellStyle getCs_int_10b() {
		return cs_int_10b;
	}

	public void setCs_int_10b(CellStyle cs_int_10b) {
		this.cs_int_10b = cs_int_10b;
	}

	public CellStyle getCs_int_10bi() {
		return cs_int_10bi;
	}

	public void setCs_int_10bi(CellStyle cs_int_10bi) {
		this.cs_int_10bi = cs_int_10bi;
	}

	public CellStyle getCs_int_10i() {
		return cs_int_10i;
	}

	public void setCs_int_10i(CellStyle cs_int_10i) {
		this.cs_int_10i = cs_int_10i;
	}

	public CellStyle getCs_left_10() {
		return cs_left_10;
	}

	public void setCs_left_10(CellStyle cs_left_10) {
		this.cs_left_10 = cs_left_10;
	}

	public CellStyle getCs_left_10b() {
		return cs_left_10b;
	}

	public void setCs_left_10b(CellStyle cs_left_10b) {
		this.cs_left_10b = cs_left_10b;
	}

	public CellStyle getCs_left_10bi() {
		return cs_left_10bi;
	}

	public void setCs_left_10bi(CellStyle cs_left_10bi) {
		this.cs_left_10bi = cs_left_10bi;
	}

	public CellStyle getCs_left_10i() {
		return cs_left_10i;
	}

	public void setCs_left_10i(CellStyle cs_left_10i) {
		this.cs_left_10i = cs_left_10i;
	}

	public boolean isCustom() {
		return isCustom;
	}

	public void setCustom(boolean isCustom) {
		this.isCustom = isCustom;
	}

	public String getKieu_chu_bold() {
		return kieu_chu_bold;
	}

	public void setKieu_chu_bold(String kieu_chu_bold) {
		this.kieu_chu_bold = kieu_chu_bold;
	}

	public String getKieu_chu_italic() {
		return kieu_chu_italic;
	}

	public void setKieu_chu_italic(String kieu_chu_italic) {
		this.kieu_chu_italic = kieu_chu_italic;
	}

	public String getKieu_chu_bold_italic() {
		return kieu_chu_bold_italic;
	}

	public void setKieu_chu_bold_italic(String kieu_chu_bold_italic) {
		this.kieu_chu_bold_italic = kieu_chu_bold_italic;
	}

	public String getTruong_kieu_chu() {
		return truong_kieu_chu;
	}

	public void setTruong_kieu_chu(String truong_kieu_chu) {
		this.truong_kieu_chu = truong_kieu_chu;
	}

	public String getReport_code() {
		return report_code;
	}

	public void setReport_code(String repord_code) {
		this.report_code = repord_code;
	}

	public Map<String, RegionStyle> getRegionMap() {
		return regionMap;
	}

	public void setRegionMap(Map<String, RegionStyle> regionMap) {
		this.regionMap = regionMap;
	}

}
